﻿// HSS.Net.Client.MainForm.cs
// ----------------------------------------------------------------------------
// Licensed under the MIT license
// http://www.opensource.org/licenses/mit-license.html
// ----------------------------------------------------------------------------
// HighSpeed-Solutions, LLC
// Copyright (c) 2001-2010
// ----------------------------------------------------------------------------
// File:       MainForm.cs
// Author:     HSS\gbanta
// Created:    08/12/2010
// Modified:   12/23/2010
// ----------------------------------------------------------------------------
namespace HSS.Net.Client
{
	#region Using Directives
	using System;
	using System.Collections.Generic;
	using System.ComponentModel;
	using System.Diagnostics;
	using System.Drawing;
	using System.Globalization;
	using System.Linq;
	using System.IO;
	using System.Net;
	using System.Text;
	using System.Threading;
	using System.Windows.Forms;
	using HSS.Net.Dns;
	#endregion

	#region MainForm
	/// <summary>
	/// MainForm
	/// </summary>
	public partial class MainForm : Form
	{
		#region Delegates
		delegate void EnableDisableEventHandler(bool enable);
		delegate void ResetDnsLogDel();
		delegate void ProcessCompleteDelegate(string output);
		#endregion

		#region Fields
		AutoCompleteStringCollection autoCompleteEmails = new AutoCompleteStringCollection();
		AutoCompleteStringCollection autoCompleteDnsQueries = new AutoCompleteStringCollection();
		Dictionary<string, SourceName> results = new Dictionary<string, SourceName>();
		Queue<string> queue = new Queue<string>();
		List<string> attachments = new List<string>();
		Stopwatch sw;
		bool _lock = false;
		bool isRunning;
		bool exitWhenComplete;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructor
		/// </summary>
		public MainForm()
		{
			InitializeComponent();

			// Smtp
			_lock = true;
			((ToolStripComboBox)this.FormattingToolStrip.Items[0]).SelectedIndex = 0;
			((ToolStripComboBox)this.FormattingToolStrip.Items[1]).SelectedIndex = 0;
			this.SetSelectionFont();
			_lock = false;
			this.txtActivityLog.ResetText();
			this.txtActivityLog.Writer.WriteLine("** HSS.Net Smtp Client (v{0}) **", HSS.Net.Mail.SmtpClient.Version);
			this.txtActivityLog.Writer.WriteLine("** {0}/{1} ({2}) **", Environment.UserDomainName, Environment.UserName, Environment.MachineName);

			// Dns
			DnsClient.Instance.ClearCache();
			DnsClient.Instance.Verbose += new EventHandler<DnsClient.VerboseEventArgs>(Instance_Verbose);
			DnsClient.VerboseMode = true;
			SetupComboBox(typeof(QClass), this.cboQueryClass);
			SetupComboBox(typeof(QType), this.cboQueryType);
			this.txtCurrentDnsServer.Text = DnsClient.Instance.DnsServer;
			this.txtTimeout.Text = DnsClient.Instance.TimeOut.ToString();
			this.chkUseCache.Checked = DnsClient.Instance.UseCache;
			this.txtAttempts.Text = DnsClient.Instance.Retries.ToString();
			this.txtDnsLog.ResetText();
			this.txtDnsLog.Writer.WriteLine("** HSS.Net.Dns DnsClient (v{0}) **", DnsClient.Version);

			#region From AutomCompleteSource
			string emailSource = HSS.Forms.AppUserData.Get("AutoCompleteEmailList", string.Empty);
			if (emailSource.Length > 0)
			{
				string[] strings = emailSource.Split(',');
				autoCompleteEmails.AddRange(strings);
			}
			this.From.AutoCompleteCustomSource = autoCompleteEmails;
			this.To.AutoCompleteCustomSource = autoCompleteEmails;
			this.Cc.AutoCompleteCustomSource = autoCompleteEmails;
			this.Bcc.AutoCompleteCustomSource = autoCompleteEmails;
			autoCompleteEmails.CollectionChanged += AutoCompletEmailChanged;
			#endregion

			#region Dns AutoCompleteSource
			string dnsSource = HSS.Forms.AppUserData.Get("AutoCompleteDnsList", string.Empty);
			if (dnsSource.Length > 0)
			{
				string[] strings = emailSource.Split(',');
				autoCompleteDnsQueries.AddRange(strings);
			}
			this.txtQuery.AutoCompleteCustomSource = autoCompleteDnsQueries;
			autoCompleteDnsQueries.CollectionChanged += AutoCompletDnsChanged;
			#endregion

			this.Shown += new EventHandler(MainForm_Shown);
		}

		void MainForm_Shown(object sender, EventArgs e)
		{
			this.From.Focus();
			this.FormClosing += new FormClosingEventHandler(MainForm_FormClosing);
		}

		void MainForm_FormClosing(object sender, FormClosingEventArgs e)
		{
			if (this.isRunning)
			{
				e.Cancel = true;
				this.exitWhenComplete = true;
				this.StopParse();
				return;
			}
		}

		#endregion

		#region Overrides
		/// <summary>
		///  Removes flicker
		/// </summary>
		protected override CreateParams CreateParams
		{
			get
			{
				CreateParams cp = base.CreateParams;
				cp.ExStyle |= 0x02000000;
				return cp;
			}
		}
		#endregion

		#region Methods

		void AutoCompletEmailChanged(object s, CollectionChangeEventArgs args)
		{
			AutoCompleteStringCollection col = s as AutoCompleteStringCollection;
			string list = string.Join(",", col.OfType<string>());
			HSS.Forms.AppUserData.Set("AutoCompleteEmailList", list);
			HSS.Forms.AppUserData.Save();
		}
		void AppendEmailSource(string emailAddress)
		{
			if (!this.autoCompleteEmails.Contains(emailAddress))
				this.autoCompleteEmails.Add(emailAddress);
		}

		void AutoCompletDnsChanged(object s, CollectionChangeEventArgs args)
		{
			AutoCompleteStringCollection col = s as AutoCompleteStringCollection;
			string list = string.Join(",", col.OfType<string>());
			HSS.Forms.AppUserData.Set("AutoCompleteDnsList", list);
			HSS.Forms.AppUserData.Save();
		}
		void AppendDnsSource(string query)
		{
			if (!this.autoCompleteDnsQueries.Contains(query))
				this.autoCompleteDnsQueries.Add(query);
		}

		void SendMailInternal(object state)
		{
			try
			{
				this.txtActivityLog.ResetText();
				Console.SetOut(this.txtActivityLog.Writer);
				System.Net.Mail.MailMessage m = state as System.Net.Mail.MailMessage;
				if (null != m)
				{
					var c = new HSS.Net.Mail.SmtpClient();
					if (!c.Send(m))
					{
						Console.WriteLine("Failed recipients summary:");
						if (null != c.FailedRecipientExceptions)
						{
							foreach (var user in c.FailedRecipientExceptions)
								Console.WriteLine("\tError: {0}", user.Message);
						}
					}
					else
					{
						Console.WriteLine("Success!:");
					}
				}
			}
			catch (Exception ex)
			{
				HSS.Forms.MessageService.ShowError(ex.Message);
			}
		}
		void SubmitDnsQuery()
		{
			this.txtDnsLog.ResetText();
			Console.SetOut(this.txtDnsLog.Writer);
			this.txtDnsLog.WordWrap = this.chkWordWrap.Checked;

			int intTimeout, intAttempts;
			int.TryParse(this.txtTimeout.Text, out intTimeout);
			int.TryParse(this.txtAttempts.Text, out intAttempts);
			DnsClient.Instance.TimeOut = intTimeout;
			DnsClient.Instance.Retries = intAttempts;
			DnsClient.Instance.DnsServer = this.txtCurrentDnsServer.Text;

			QType qType = (QType)this.cboQueryType.SelectedItem;
			QClass qClass = (QClass)this.cboQueryClass.SelectedItem;
			string query = this.txtQuery.Text;
			this.AppendDnsSource(query);

			if (qType == QType.AXFR) // zone transfers only use TCP
				this.radioButton2.Checked = true;

			if (this.radioButton1.Checked)
				DnsClient.Instance.TransportType = HSS.Net.Dns.TransportType.Udp;

			if (this.radioButton2.Checked)
				DnsClient.Instance.TransportType = HSS.Net.Dns.TransportType.Tcp;

			if (qType == QType.PTR)
			{
				IPAddress ip;
				if (IPAddress.TryParse(query, out ip))
					query = DnsClient.GetArpaFromIp(ip);
			}

			if (qType == QType.NAPTR)
				query = DnsClient.GetArpaFromEnum(query);

			Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", false);
			Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US", false);

			Console.WriteLine("");
			Console.WriteLine("Query submitted: {0} {1} {2}  ({3})", query, qType, qClass, DnsClient.Instance.DnsServer);

			sw = new Stopwatch();
			sw.Start();
			DnsClient.BeginQuery(query, qType, qClass, this.chkUseCache.Checked, SubmitDnsQueryResponse);

		}
		void SubmitDnsQueryResponse(IAsyncResult state)
		{
			sw.Stop();

			try
			{
				HSS.AsyncResult<Response> ar = (HSS.AsyncResult<Response>)state;

				// If an exception occured, it will be thrown here...
				Response response = ar.EndInvoke();

				if (!string.IsNullOrEmpty(response.Error))
				{
					Console.WriteLine("");
					Console.WriteLine("ERROR: " + response.Error);
					Console.WriteLine("");
					Console.WriteLine(">> END RESPONSE	<<");
					return;
				}

				Console.WriteLine("");
				Console.WriteLine("Received Response:");
				Console.WriteLine("");

				Console.WriteLine(">> HEADER SECTION <<");
				Console.WriteLine("");

				Console.WriteLine("{0,-32}\r\n\topcode:\t\t\t{1}\r\n\tresponse code:\t\t{2}\r\n\tid:\t\t\t{3}",
					"Status:",
					response.header.OPCODE,
					response.header.RCODE,
					response.header.ID);

				Console.WriteLine("{0,-32}\r\n\tIsResponse:\t\t{1}\r\n\tIsAuthoritative:\t{2}\r\n\tIsRecursionDesired:\t{3}\r\n\tIsRecursionAvailable:\t{4}\r\n\tTruncated:\t\t{5}",
					"Flags:",
					response.header.QR,
					response.header.AA,
					response.header.RD,
					response.header.RA,
					response.header.TC);

				Console.WriteLine("{0,-32}\r\n\tQueries:\t\t{1}\r\n\tAnswers:\t\t{2}\r\n\tAuthorities:\t\t{3}\r\n\tAdditionals:\t\t{4}",
					"Records:",
					response.Questions.Count,
					response.Answers.Count,
					response.Authorities.Count,
					response.Additionals.Count);
				Console.WriteLine("");

				Console.WriteLine("");
				Console.WriteLine(">> MESSAGE SECTION <<");
				Console.WriteLine("");
				Console.WriteLine(RR.GetHeaderLabels());
				Console.WriteLine("");

				if (response.Questions.Count > 0)
				{
					Console.WriteLine("QUESTION:");
					foreach (Question question in response.Questions)
						Console.WriteLine(question);
					Console.WriteLine("");
				}

				if (response.Answers.Count > 0)
				{
					Console.WriteLine("ANSWER:");
					foreach (AnswerRR answerRR in response.Answers)
						Console.WriteLine(answerRR);
					Console.WriteLine("");
				}

				if (response.Authorities.Count > 0)
				{
					Console.WriteLine("AUTHORITY:");
					foreach (AuthorityRR authorityRR in response.Authorities)
						Console.WriteLine(authorityRR);
					Console.WriteLine("");
				}

				if (response.Additionals.Count > 0)
				{
					Console.WriteLine("ADDITIONAL:");
					foreach (AdditionalRR additionalRR in response.Additionals)
						Console.WriteLine(additionalRR);
					Console.WriteLine("");
				}

				Console.WriteLine("");
				Console.WriteLine(">> TRACE SECTION <<");
				Console.WriteLine("");

				var dnsHostName = "N/A";
				try
				{
					var entry = System.Net.Dns.GetHostEntry(response.Server.Address);
					if (null != entry)
						dnsHostName = entry.HostName;
				}
				catch
				{
					dnsHostName = response.Server.Address.ToString();
				}
				Console.WriteLine("ELAPSED:   {0} msec", sw.ElapsedMilliseconds);
				Console.WriteLine("SERVER:    {0}:{1} ({2})", response.Server.Address, response.Server.Port, dnsHostName);
				Console.WriteLine("TIMESTAMP: " + response.TimeStamp.ToString("ddd MMM dd HH:mm:ss yyyy", new System.Globalization.CultureInfo("en-US")));
				Console.WriteLine("SIZE:      " + response.MessageSize + " bytes");
				Console.WriteLine("");
				Console.WriteLine(">> END RESPONSE	<<");
			}
			catch (Exception ex)
			{
				ResetDnsLog();
				Console.Write(ex.ToString());
			}
			this.txtCurrentDnsServer.Text = DnsClient.Instance.DnsServer;
		}
		void ResetDnsLog()
		{
			if (this.InvokeRequired)
				this.Invoke((new ResetDnsLogDel(ResetDnsLog)));
			else
				this.txtDnsLog.ResetText();
		}
		void EnableDisableSendButton(bool enable)
		{
			if (this.btnSend.InvokeRequired)
			{
				EnableDisableEventHandler obj = new EnableDisableEventHandler(this.EnableDisableSendButton);
				this.Invoke(obj, new object[] { enable });
			}
			else
			{
				this.btnSend.Enabled = enable;
			}
		}
		bool CheckInputValidation(string from, string to, string cc, string bcc)
		{
			if (string.IsNullOrEmpty(from))
			{
				MessageBox.Show(this, "You must provide sender email address.", "Email Client", MessageBoxButtons.OK, MessageBoxIcon.Information);
				return false;
			}
			else if (!string.IsNullOrEmpty(to) ||
					!string.IsNullOrEmpty(cc) ||
					!string.IsNullOrEmpty(bcc))
			{
				return true;
			}
			else if (string.IsNullOrEmpty(to) &&
					string.IsNullOrEmpty(cc) &&
					string.IsNullOrEmpty(bcc))
			{
				MessageBox.Show(this, "You must provide recipient email address.", "Email Client", MessageBoxButtons.OK, MessageBoxIcon.Information);
				return false;
			}

			return true;
		}
		bool RecipientsEmailValidation(string recipient)
		{
			string[] splits = recipient.Split(new char[] { ',', ';' });

			for (int i = 0; i < splits.Length; i++)
			{
				if (this.EmailValidation(splits[i]))
				{
					continue;
				}
				else
				{
					return false;
				}
			}

			return true;
		}
		bool EmailValidation(string email)
		{
			return false;
		}
		void SetSelectionFont()
		{
			if (this._lock == true)
				return;
			else
			{
				System.Drawing.FontStyle style = System.Drawing.FontStyle.Regular;
				if (((ToolStripButton)this.FormattingToolStrip.Items[3]).Checked)
				{
					style |= System.Drawing.FontStyle.Bold;
				}
				if (((ToolStripButton)this.FormattingToolStrip.Items[4]).Checked)
				{
					style |= System.Drawing.FontStyle.Italic;
				}
				if (((ToolStripButton)this.FormattingToolStrip.Items[5]).Checked)
				{
					style |= System.Drawing.FontStyle.Underline;
				}

				this.MailMessage.SelectionFont = new Font(((ToolStripComboBox)this.FormattingToolStrip.Items[0]).Text, Convert.ToSingle(((ToolStripComboBox)this.FormattingToolStrip.Items[1]).Text), style);
				this.MailMessage.Focus();
			}
		}
		bool ParseRecipients(string listOfRecipients, List<System.Net.Mail.MailAddress> list)
		{
			if (listOfRecipients.Length > 0)
			{
				string[] split = listOfRecipients.Split(new char[] { ',', ';' });

				for (int j = 0; j < split.Length; j++)
				{
					string address = split[j].Trim();
					if (!string.IsNullOrEmpty(address))
					{
						try
						{
							HSS.Net.Mail.EmailAddress ea = new HSS.Net.Mail.EmailAddress(address);
							if (ea.IsValid)
							{
								System.Net.Mail.MailAddress ma = new System.Net.Mail.MailAddress(address);
								list.Add(ma);
							}
							else
							{
								HSS.Forms.MessageService.ShowWarningFormatted("Email Address", "The following address [ {0} ] is not valid.", address);
								list.Clear();
								return false;
							}
						}
						catch
						{
							HSS.Forms.MessageService.ShowWarningFormatted("Email Address", "The following address [ {0} ] is not valid.", address);
							list.Clear();
							return false;
						}
					}
				}
			}
			return true;
		}
		string GetByteString(double fileSize)
		{
			if (fileSize < 1024.0)
				return string.Format("{0:N0} bytes", fileSize);

			if (fileSize < 1048576.0)
				return string.Format("{0:N1} KB", fileSize / 1024.0);

			if (fileSize < 1073741824.0)
				return string.Format("{0:N1} MB", fileSize / 1048576.0);

			return string.Format("{0:N1} GB", fileSize / 1073741824.0);
		}
		void ResetDnsClient()
		{
			this.txtCurrentDnsServer.Text = DnsClient.GetDnsServers()[0].Address.ToString();
		}

		void ParseList()
		{
			try
			{
				// Reset
				this.results.Clear();
				this.txtOutput.Clear();
				this.queue.Clear();
				if (this.txtInput.TextLength == 0)
					return;


				this.Cursor = Cursors.WaitCursor;
				this.tsmParseList.Enabled = false;
				this.tsmClear.Enabled = false;
				this.txtInput.Enabled = false;
				this.txtOutput.Enabled = false;
				this.tsmStop.Enabled = true;
				this.isRunning = true;

				// Queue up the list
				string[] ips = this.txtInput.Text.Split(Environment.NewLine.ToCharArray());
				foreach (var query in ips)
				{
					if (query.Length > 0)
					{
						IPAddress ip;
						if (IPAddress.TryParse(query, out ip))
							this.queue.Enqueue(DnsClient.GetArpaFromIp(ip));
						else
							this.queue.Enqueue("Error: " + query);
					}
				}

				if (this.queue.Count == 1)
					this.txtOutput.Text = "Processing " + this.queue.Count.ToString() + " IP Address.\r\nPlease wait...\r\n";
				else
					this.txtOutput.Text = "Processing " + this.queue.Count.ToString() + " IP Addresses.\r\nPlease wait...\r\n";

				// Process the queue
				this.ProcessQueue();
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.Message, "Bulk IP Resolution", MessageBoxButtons.OK);
			}
		}
		void StopParse()
		{
			this.tsmStop.Enabled = false;
			this.isRunning = false;
		}
		void ProcessQueue()
		{
			if (this.queue.Count > 0 && this.isRunning)
			{
				string q = queue.Dequeue();
				if (q.StartsWith("Error"))
				{
					results.Add(q, new SourceName() { Name = q, IpAddresses = new List<string>() });
					this.ProcessQueue();
				}
				else
					DnsClient.BeginQuery(q, HSS.Net.Dns.QType.PTR, QClass.IN, false, ProcessResponse);
			}
			else
				this.ProcessResults();
		}
		void ProcessResponse(IAsyncResult async)
		{
			AsyncResult<Response> result = async as AsyncResult<Response>;
			var response = result.EndInvoke();

			if (null != response)
			{
				if (response.Answers.Count > 0)
				{
					string name = response.Answers[0].RECORD.ToString();
					string domain = ExtractBaseDomain(name);
					if (!results.ContainsKey(domain))
						results.Add(domain, new SourceName() { Name = domain, IpAddresses = new List<string>() });
					if (results[domain].IpAddresses.Count < 3) // Only add the first three query request.
						results[domain].IpAddresses.Add(name);
					else if (results[domain].IpAddresses.Count < 4)
						results[domain].IpAddresses.Add(" truncated...");
				}
				else
				{
					string domain = "Failed query: " + response.Questions[0].QName;
					if (!results.ContainsKey(domain))
						results.Add(domain, new SourceName() { Name = domain, IpAddresses = new List<string>() });
					results[domain].IpAddresses.Add("no answers...");
				}
			}

			// Continue...
			this.ProcessQueue();
		}
		void ProcessResults()
		{
			var sb = new StringBuilder();
			if (results.Count > 0)
			{
				int max = 0;
				foreach (var result in results)
				{
					if (max < result.Value.Name.Length / 8)
						max = result.Value.Name.Length / 8;
				}

				string formatTab = "{1}";
				string format;
				foreach (var result in results.OrderBy(a => a.Value.Name))
				{
					format = "{0}{1}";
					var src = result.Value;
					int w = src.Name.Length / 8;
					if (w < max)
					{
						for (int i = 0; i < (max - w); i++)
							format += formatTab;
					}
					if (src.IpAddresses.Count > 0)
						format += "(";
					sb.AppendFormat(format, src.Name, "	");
					if (src.IpAddresses.Count > 0)
					{
						foreach (var resultIps in src.IpAddresses)
							sb.Append(resultIps + ", ");
						sb.Remove(sb.Length - 2, 2);
						sb.Append(")" + Environment.NewLine);
					}
				}
			}
			else
			{
				sb.AppendLine("No results.");
			}
			sb.AppendLine();
			sb.AppendLine("Completed.");

			this.ProcessComplete(sb.ToString());

		}
		void ProcessComplete(string output)
		{
			if (this.exitWhenComplete)
			{
				Application.Exit();
				return;
			}

			if (this.InvokeRequired)
				this.BeginInvoke(new ProcessCompleteDelegate(ProcessComplete), output);
			else
			{
				this.tsmStop.Enabled = false;
				this.txtOutput.AppendText(output);
				this.txtOutput.Enabled = true;
				this.txtInput.Enabled = true;
				this.tsmParseList.Enabled = true;
				this.tsmClear.Enabled = true;
				this.Cursor = Cursors.Default;
				this.isRunning = false;
			}
		}
		string ExtractBaseDomain(string name)
		{
			string[] domainParts = name.Split('.');
			string domain = domainParts[domainParts.Length - 1];
			if (domainParts.Length >= 3)
				return domainParts[domainParts.Length - 3] + "." + domainParts[domainParts.Length - 2];
			if (domainParts.Length >= 2)
				return domainParts[domainParts.Length - 2] + "." + domainParts[domainParts.Length - 1];
			return domain;
		}

		static void SetupComboBox(System.Type type, ComboBox comboBox)
		{
			comboBox.Items.Clear();
			Array types = Enum.GetValues(type);
			for (int intI = 0; intI < types.Length; intI++)
				comboBox.Items.Add(types.GetValue(intI));
			comboBox.SelectedIndex = 0;
		}
		static Bitmap CreateFontColorIcon(Color color)
		{
			var bmp = Properties.Resources.fontcolor;

			for (int x = 0; x < bmp.Width; x++)
			{
				for (int y = 12; y < bmp.Height; y++)
				{
					bmp.SetPixel(x, y, color);
				}
			}

			return bmp;
		}
		static Bitmap CreateFontBackColorIcon(Color color)
		{
			Bitmap bmp = Properties.Resources.fontbackcolor;

			for (int x = 0; x < bmp.Width; x++)
			{
				for (int y = 12; y < bmp.Height; y++)
				{
					bmp.SetPixel(x, y, color);
				}
			}

			return bmp;
		}

		#endregion

		#region Event Handlers
		private void Instance_Verbose(object sender, DnsClient.VerboseEventArgs e)
		{
			Console.WriteLine(e.Message);
		}
		private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			this.ResetDnsClient();
		}
		private void Send_Click(object sender, EventArgs e)
		{
			#region Text Validation
			if (this.From.Text.Length == 0)
			{
				HSS.Forms.MessageService.ShowError("Missing the from Address.");
				return;
			}
			if (this.To.Text.Length == 0 && this.Cc.Text.Length == 0 && this.Bcc.Text.Length == 0)
			{
				HSS.Forms.MessageService.ShowError("Missing the a To, Cc, or Bcc Address and at least one email address is required.");
				return;
			}
			if (this.Subject.Text.Length == 0)
			{
				HSS.Forms.MessageService.ShowError("Missing the subject line.");
				return;
			}
			#endregion

			this.EnableDisableSendButton(false);
			this.txtActivityLog.ResetText();
			System.Net.Mail.MailMessage m = new System.Net.Mail.MailMessage();
			try
			{
				List<System.Net.Mail.MailAddress> addresses = new List<System.Net.Mail.MailAddress>();

				if (ParseRecipients(this.To.Text, addresses))
				{
					foreach (var add in addresses)
					{
						m.To.Add(add);
						this.AppendEmailSource(add.Address);
					}
					addresses.Clear();
				}
				else
					return;

				if (ParseRecipients(this.Cc.Text, addresses))
				{
					foreach (var add in addresses)
					{
						m.CC.Add(add);
						this.AppendEmailSource(add.Address);
					}
					addresses.Clear();
				}
				else
					return;

				if (ParseRecipients(this.Bcc.Text, addresses))
				{
					foreach (var add in addresses)
					{
						m.Bcc.Add(add);
						this.AppendEmailSource(add.Address);
					}
					addresses.Clear();
				}
				else
					return;

				m.Subject = this.Subject.Text;

				Rtf2Html rtf = new Rtf2Html();
				string Html = rtf.ConvertRtfToHtml(this.MailMessage);
				m.Body = Html;
				m.IsBodyHtml = true;

				m.From = new System.Net.Mail.MailAddress(this.From.Text);
				this.AppendEmailSource(this.From.Text);

				if (this.attachments.Count > 0)
				{
					foreach (string x in this.attachments)
						m.Attachments.Add(new System.Net.Mail.Attachment(x));
				}
				new System.Threading.Thread(SendMailInternal).Start(m);


			}
			catch (Exception ex)
			{
				MessageBox.Show(this, ex.Message, "HSS Net Client", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
			finally
			{
				this.EnableDisableSendButton(true);
				this.ProgressLabel.Text = "Ready";
			}
		}
		private void btnSubmitDnsQuery_Click(object sender, EventArgs e)
		{
			this.SubmitDnsQuery();
		}
		private void txtQuery_KeyUp(object sender, KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Enter)
			{
				this.SubmitDnsQuery();
			}
		}
		private void SmtpClear_Click(object sender, EventArgs e)
		{
			this.From.Text = "";
			this.To.Text = "";
			this.Cc.Text = "";
			this.Bcc.Text = "";
			this.Subject.Text = "";
			this.MailMessage.Text = "";
			this.Attachments.Clear();
		}
		private void EmailTimer_Tick(object sender, EventArgs e)
		{
			if (From.ContainsFocus)
				this.From.BackColor = Color.Ivory;
			else
				this.From.BackColor = SystemColors.Window;

			if (To.ContainsFocus)
				this.To.BackColor = Color.Ivory;
			else
				this.To.BackColor = SystemColors.Window;

			if (Cc.ContainsFocus)
				this.Cc.BackColor = Color.Ivory;
			else
				this.Cc.BackColor = SystemColors.Window;

			if (Bcc.ContainsFocus)
				this.Bcc.BackColor = Color.Ivory;
			else
				this.Bcc.BackColor = SystemColors.Window;

			if (Subject.ContainsFocus)
				this.Subject.BackColor = Color.Ivory;
			else
				this.Subject.BackColor = SystemColors.Window;
		}
		private void MailMessage_SelectionChanged(object sender, EventArgs e)
		{
			if (this.MailMessage.SelectionFont == null)
				return;
			else
			{
				this._lock = true;

				((ToolStripComboBox)this.FormattingToolStrip.Items[0]).Text = this.MailMessage.SelectionFont.Name;
				((ToolStripComboBox)this.FormattingToolStrip.Items[1]).Text = this.MailMessage.SelectionFont.Size.ToString();
				((ToolStripButton)this.FormattingToolStrip.Items[3]).Checked = this.MailMessage.SelectionFont.Bold;
				((ToolStripButton)this.FormattingToolStrip.Items[4]).Checked = this.MailMessage.SelectionFont.Italic;
				((ToolStripButton)this.FormattingToolStrip.Items[5]).Checked = this.MailMessage.SelectionFont.Underline;
				((ToolStripButton)this.FormattingToolStrip.Items[7]).Image = CreateFontColorIcon(this.MailMessage.SelectionColor);
				((ToolStripButton)this.FormattingToolStrip.Items[8]).Image = CreateFontBackColorIcon(this.MailMessage.SelectionBackColor);

				this._lock = false;
			}
		}
		private void AttachmentToolStrip_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
		{
			if (e.ClickedItem.Tag == null)
				return;
			else if (e.ClickedItem.Tag.ToString() == "Add")
			{
				using (OpenFileDialog dialog = new OpenFileDialog())
				{
					dialog.Multiselect = true;
					if (dialog.ShowDialog() == DialogResult.OK)
					{
						foreach (string file in dialog.FileNames)
						{
							ListViewItem item = new ListViewItem(Path.GetFileName(file) + " (" + GetByteString((double)new FileInfo(file).Length) + ")");
							item.ToolTipText = file;
							item.ImageIndex = 0;
							item.Tag = file;
							this.attachments.Add(file);
							this.Attachments.Items.Add(item);
						}
					}
				}
			}
			else if (e.ClickedItem.Tag.ToString() == "Delete")
			{
				if (this.Attachments.SelectedItems.Count > 0)
				{
					this.attachments.Remove(this.Attachments.SelectedItems[0].Tag.ToString());
					this.Attachments.SelectedItems[0].Remove();
				}
			}
		}
		private void Attachments_SelectedIndexChanged(object sender, EventArgs e)
		{
			if (this.Attachments.SelectedItems.Count > 0)
			{
				this.AttachmentToolStrip.Items[1].Enabled = true;
			}
			else
			{
				this.AttachmentToolStrip.Items[1].Enabled = false;
			}
		}
		private void FontStyle_SelectedIndexChanged(object sender, EventArgs e)
		{
			this.SetSelectionFont();
		}
		private void FontSize_SelectedIndexChanged(object sender, EventArgs e)
		{
			this.SetSelectionFont();
		}
		private void Bold_Click(object sender, EventArgs e)
		{
			if (((ToolStripButton)this.FormattingToolStrip.Items[3]).Checked)
			{
				((ToolStripButton)this.FormattingToolStrip.Items[3]).Checked = false;
			}
			else
			{
				((ToolStripButton)this.FormattingToolStrip.Items[3]).Checked = true;
			}

			this.SetSelectionFont();
		}
		private void Italic_Click(object sender, EventArgs e)
		{
			if (((ToolStripButton)this.FormattingToolStrip.Items[4]).Checked)
			{
				((ToolStripButton)this.FormattingToolStrip.Items[4]).Checked = false;
			}
			else
			{
				((ToolStripButton)this.FormattingToolStrip.Items[4]).Checked = true;
			}

			this.SetSelectionFont();
		}
		private void Underline_Click(object sender, EventArgs e)
		{
			if (((ToolStripButton)this.FormattingToolStrip.Items[5]).Checked)
			{
				((ToolStripButton)this.FormattingToolStrip.Items[5]).Checked = false;
			}
			else
			{
				((ToolStripButton)this.FormattingToolStrip.Items[5]).Checked = true;
			}

			this.SetSelectionFont();
		}
		private void FontColor_Click(object sender, EventArgs e)
		{
			using (ColorDialog dialog = new ColorDialog())
			{
				if (dialog.ShowDialog(this) == DialogResult.OK)
				{
					this.MailMessage.SelectionColor = dialog.Color;
					((ToolStripButton)this.FormattingToolStrip.Items[7]).Image = CreateFontColorIcon(dialog.Color);
				}
			}
		}
		private void FontBackgroundColor_Click(object sender, EventArgs e)
		{
			using (ColorDialog dialog = new ColorDialog())
			{
				if (dialog.ShowDialog(this) == DialogResult.OK)
				{
					this.MailMessage.SelectionBackColor = dialog.Color;
					((ToolStripButton)this.FormattingToolStrip.Items[8]).Image = CreateFontBackColorIcon(dialog.Color);
				}
			}
		}
		private void mnuHelpAbout_Click(object sender, EventArgs e)
		{
			string about = "HSS Net Client  v" + HSS.Net.Mail.SmtpClient.Version;
			about += Environment.NewLine;
			about += "HSS.Net.Mail.SmtpClient v" + HSS.Net.Mail.SmtpClient.Version;
			about += Environment.NewLine;
			about += "HSS.Net.Dns.DnsClient v" + HSS.Net.Dns.DnsClient.Version;
			about += Environment.NewLine;
			about += Environment.NewLine;
			about += "© " + DateTime.Now.Year.ToString() + " HighSpeed-Solutions, LLC";

			HSS.Forms.MessageService.ShowMessage(about, "About...");
		}
		private void mnuFile_Exit_Click(object sender, EventArgs e)
		{
			//this.Close();
			CancelEventArgs c = new CancelEventArgs();
			Application.Exit(c);
			if (c.Cancel)
				HSS.Forms.MessageService.ShowMessage("Exit was canceled!");
		}
		private void tsmParseList_Click(object sender, EventArgs e)
		{
			this.ParseList();
		}
		private void tsmStop_Click(object sender, EventArgs e)
		{
			this.StopParse();
		}
		private void tsmClear_Click(object sender, EventArgs e)
		{
			this.txtInput.ResetText();
			this.txtOutput.ResetText();
		}
		#endregion

		#region Rtf2Html
		internal class Rtf2Html
		{
			readonly string RTF_LB = Convert.ToChar(10).ToString();
			readonly string RTF_SP = " ";
			readonly string HTML_BR = "<br />";

			public string ConvertRtfToHtml(RichTextBox rtfBox)
			{
				string HTML = string.Empty;
				try
				{
					string style = string.Empty;
					string lastStyle = string.Empty;
					StringBuilder html = new StringBuilder();

					if (rtfBox.Text.Length == 0)
						return "<html></html>";

					// Begin Html Body
					html.AppendLine("<body>");

					// Select first character
					rtfBox.Select(0, 1);
					string charValue = rtfBox.Text.Substring(0, 1);

					if (charValue == RTF_LB)
						html.Append(HTML_BR);
					if (charValue == RTF_SP)
						html.Append("&nbsp;");

					// Include first 'style' parameters in the HTML
					style = this.GetCurrentStyle(rtfBox);
					lastStyle = style;
					html.Append("<span style=\"" + style + "\">");

					// Add the actual character
					html.Append(charValue);

					// Loop around all remaining characters
					for (int charIndex = 1; charIndex < rtfBox.Text.Length; charIndex++)
					{
						// Select current character
						rtfBox.Select(charIndex, 1);
						charValue = rtfBox.Text.Substring(charIndex, 1);

						// Add space and skip formatting
						if (charValue == RTF_SP)
						{
							html.Append(RTF_SP);
							continue;
						}

						#region If this is a line break, add HTML tag
						if (charValue == RTF_LB)
						{
							html.AppendLine("</span>" + HTML_BR);

							// Check/implement any changes in style
							style = this.GetCurrentStyle(rtfBox);
							lastStyle = style;
							html.Append("<span style=\"" + style + "\">");
							continue;
						}
						#endregion

						// Check/implement any changes in style
						style = this.GetCurrentStyle(rtfBox);
						if (!string.IsNullOrEmpty(style) && lastStyle != style)
						{
							lastStyle = style;
							html.AppendLine("</span>");
							html.Append("<span style=\"" + style + "\">");
						}

						if (rtfBox.SelectionType == RichTextBoxSelectionTypes.Text)
							// Add the actual character
							html.Append(charValue);
					}

					// Terminate outstanding HTML tags
					html.AppendLine("</span>");
					html.Append("</body></html>");

					// Styles
					StringBuilder headTag = new StringBuilder();
					headTag.AppendLine("<head>");
					headTag.AppendLine("<Title>email</Title>");
					headTag.Append("</head>");

					html.Insert(0, headTag.ToString() + "\r\n");
					html.Insert(0, "<html>");

					// Set HTML
					HTML = html.ToString();
				}
				catch (Exception ex)
				{
					MessageBox.Show("Error parsing RTF to HTML...\r\n\r\n" + ex.Message, "HSS Net Client", MessageBoxButtons.OK);
				}
				finally
				{
					if (null != rtfBox)
						rtfBox.Select(0, 0);
				}

				return HTML;
			}
			string GetCurrentStyle(RichTextBox rtfBox)
			{
				string textColour;
				string backgroundColour;
				bool bold;
				bool italic;
				bool underline;
				string font;
				short size;

				string style = string.Empty;
				try
				{
					textColour = "#" + rtfBox.SelectionColor.R.ToString("X2") + rtfBox.SelectionColor.G.ToString("X2") + rtfBox.SelectionColor.B.ToString("X2");
					backgroundColour = "#" + rtfBox.SelectionBackColor.R.ToString("X2") + rtfBox.SelectionBackColor.G.ToString("X2") + rtfBox.SelectionBackColor.B.ToString("X2");

					if (null == rtfBox.SelectionFont)
					{
						bold = false;
						italic = false;
						underline = false;
						font = rtfBox.Font.FontFamily.Name;
						size = Convert.ToInt16(rtfBox.Font.Size);
					}
					else
					{
						bold = rtfBox.SelectionFont.Bold;
						italic = rtfBox.SelectionFont.Italic;
						underline = rtfBox.SelectionFont.Underline;
						font = rtfBox.SelectionFont.FontFamily.Name;
						size = Convert.ToInt16(rtfBox.SelectionFont.Size);
					}
					style = string.Format("font-family:{0};text-decoration:{1};font-weight:{2};font-style:{3};font-size:{4}pt;color:{5};background-color:{6};",
						font,
						(underline ? "underline" : "normal"),
						(bold ? "bold" : "normal"),
						(italic ? "italic" : "normal"),
						size,
						textColour,
						backgroundColour);
				}
				catch { style = string.Empty; }

				return style;
			}
		}
		#endregion
	}
	#endregion

	#region SourceName
	class SourceName
	{
		public string Name { get; set; }
		public List<string> IpAddresses { get; set; }
	}
	#endregion
}